import base64
import hashlib
import hmac
import json
import os
import random
import re
import socket
import subprocess
import time
import urllib
from datetime import datetime
from urllib.parse import urlencode

import psutil
import requests

amazon_us_numbers_field = ['item_diameter_derived', 'size_name', 'number_of_blades', 'load_capacity', 'number_of_drawers', 'amperage', 'number_of_heating_elements', 'mfg_maximum', 'hole_count', 'item_offset', 'maximum_reading_interest_age',
                           'fda_premarket_approval_number_pma', 'display_size', 'viewing_angle', 'tread_depth', 'number_of_batteries1', 'wheel_size', 'number_of_sets', 'pitch_circle_diameter', 'rim_size', 'computer_memory_size', 'website_shipping_weight', 'frame_size',
                           'number_of_pieces', 'tire_aspect_ratio', 'memory_storage_capacity', 'button_quantity', 'hard_disk_size', 'speed_rating', 'occupancy', 'number_of_items', 'wattage', 'frequency',
                           'cable_length', 'supported_devices_quantity', 'computer_cpu_speed', 'maximum_weight_recommendation', 'mfg_minimum', 'total_usb_ports', 'minimum_reading_interest_age', 'number_of_compartments', 'maximum_compatible_size', 'item_package_quantity', 'number_of_doors',
                           'caliber',
                           'footwear_size_class', 'rim_width', 'number_of_handles', 'cost_price', 'liquid_volume', 'number_of_shelves', 'capacity', 'band_size_num', 'storage_volume', 'number_of_panels', 'seating_capacity',
                           'number_of_players', 'each_unit_count', 'battery_average_life', 'voltage', 'cutting_width', 'net_content_count', 'number_of_boxes', 'maximum_stride_length', 'maximum_weight_capacity', 'sheet_count', 'pages', 'number_of_speeds', 'runtime',
                           'minimum_compatible_size', 'battery_capacity']


def generate_sign(secret, timestamp):
    secret_enc = secret.encode('utf-8')
    string_to_sign = '{}\n{}'.format(timestamp, secret)
    string_to_sign_enc = string_to_sign.encode('utf-8')
    hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
    sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
    return sign


def load_json(file_path):
    """
    加载指定路径的 JSON 文件并返回其内容。

    :param file_path: JSON 文件的路径（字符串）
    :return: JSON 文件的内容（通常是字典或列表）
    """
    try:
        # 打开文件并读取内容
        with open(file_path, 'r', encoding='utf-8') as file:
            data = json.load(file)  # 使用 json.load 解析 JSON 数据
        return data
    except FileNotFoundError:
        print(f"错误：文件未找到，请检查路径是否正确：{file_path}")
    except json.JSONDecodeError:
        print(f"错误：文件内容不是有效的 JSON 格式：{file_path}")
    except Exception as e:
        print(f"发生未知错误：{e}")


def send_dingtalk_message(message, msg_typ='text',
                          webhook_url='https://oapi.dingtalk.com/robot/send?access_token=64ba05e30b0e60b46fbdc4d614b92d042cd5d7c333a94b148e33613a99a7c7f6', secret='SEC6c1003f356986e177b6a7dc8ca39bb69fd395b4e786550e636c431afc7b48a30'):
    headers = {
        'Content-Type': 'application/json',
    }
    data = {}
    # 构建消息体
    if msg_typ == 'text':
        data = {
            "msgtype": "text",
            "text": {
                "content": message
            }
        }
    if msg_typ == 'markdown':
        data = {
            "msgtype": "markdown",
            "markdown": {
                "title": "嘻嘻🤭",
                "text": message
            }
        }
    try:
        # 如果提供了secret，则启用签名机制
        if secret:
            timestamp = str(round(time.time() * 1000))
            sign = generate_sign(secret, timestamp)
            webhook_url = f"{webhook_url}&timestamp={timestamp}&sign={sign}"

        response = requests.post(webhook_url, headers=headers, data=json.dumps(data), timeout=15)
        response.raise_for_status()
        result = response.json()
        return result
    except requests.exceptions.RequestException as e:
        print(f"req exception: {e}")
        return None


def sleep_random_duration(start=1, end=2):
    # 生成0到2秒之间的随机浮点数
    random_duration = random.uniform(start, end)
    time.sleep(random_duration)


def extract_and_merge_json(text: str):
    if text is None:
        return None
    text = str(text).strip()
    if text == 0:
        return {}
    try:
        # 使用正则表达式匹配外层的 JSON 对象
        json_match = re.search(r'\{.*?\}|\[.*?\]', text, re.DOTALL)
        if not json_match:
            print(f"没有找到有效的 JSON 部分:{text}")
            return {}
        json_string = json_match.group()
        return json.loads(json_string)
    except json.JSONDecodeError as e:
        return {}


def check_and_kill_port(port: int):
    try:
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            s.settimeout(1)
            result = s.connect_ex(("127.0.0.1", port))
            if result == 0:  # 端口被占用
                print(f"Port {port} is in use. Attempting to kill the process...")
                if os.name == "posix":  # Linux/MacOS
                    command = f"lsof -ti:{port}"
                else:  # Windows
                    command = f"netstat -ano | findstr :{port}"
                result = subprocess.check_output(command, shell=True).decode().strip()
                if result:
                    pid = result.split()[-1] if os.name != "posix" else result.split('\n')[0]
                    os.kill(int(pid), 9)
                    print(f"Process {pid} on port {port} was killed.")
    except Exception as e:
        print(f"Error checking port {port}: {e}")


def extract_field_number(field, filed_value, default=None):
    if isinstance(filed_value, (int, float)):
        return filed_value
    if isinstance(filed_value, str) and field in amazon_us_numbers_field:
        word_to_num = {'zero': 0, 'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5, 'six': 6, 'seven': 7, 'eight': 8, 'nine': 9, 'ten': 10}
        match = re.search(r'(\d+(\.\d+)?)', filed_value)
        if match:
            return round(float(match.group(1)), 2)
        else:
            for word, num in word_to_num.items():
                if word in filed_value.lower():
                    return num
            return 1
    return filed_value if default is None else default


def split_langer_txt(words, max_char_count=240):
    if len(words) < 1:
        return ""
    # 用于拼接符合字符限制的结果
    result = []
    char_count = 0
    # 以分号为分隔符拆分单词
    for word in words:
        # 检查加入当前段落后字符数是否超出最大限制
        if char_count + len(word) > max_char_count:
            break
        result.append(word)  # 将符合条件的单词加入结果列表
        char_count += len(word)
    # 返回拼接后的字符串，使用分号连接
    return ";".join(result)


# 定义一个函数来去除敏感词
def remove_sensitive_words(text, sensitive_words):
    if text is None or len(text) < 1 or not isinstance(text, str):
        return ""
    # 将敏感词列表转换为正则表达式，忽略大小
    pattern = r'\b(?:' + '|'.join(map(re.escape, sensitive_words)) + r')\b'
    # 使用 re.sub() 替换敏感词为 ''（空字符串）
    cleaned_text = re.sub(pattern, '', text, flags=re.IGNORECASE)
    return cleaned_text


# 固定第一位和第二位置,后面位置图片顺序随机打乱
def shuffle_list_except_first_two_elements(lst):
    # 如果列表长度小于等于3，则无需操作，直接返回原列表
    if len(lst) <= 3:
        return lst
    # 固定第一、第二号元素，对剩余的元素进行随机交换顺序
    fixed_part = lst[:2]
    variable_part = lst[2:]
    # 随机打乱第三号及其之后的元素
    random.shuffle(variable_part)
    # 合并固定部分和打乱后的部分
    new_list = fixed_part + variable_part
    return new_list


def split_html_tag(html_text):
    if html_text is None or len(html_text) < 1:
        return ""
    result = ""
    char_count = 0
    max_char_count = 1950
    # 直接从头开始截取html_text，确保不破坏任何HTML标签
    while char_count < max_char_count and html_text:
        end_pos = html_text.find('>', char_count)
        if end_pos == -1:  # 如果没有找到更多的闭合标签，则结束循环
            break
        potential_new_count = char_count + end_pos - char_count + 1
        if potential_new_count > max_char_count:
            break
        result += html_text[:end_pos + 1]
        char_count = potential_new_count
        html_text = html_text[end_pos + 1:]
    return result


def filter_table_data(html_content):
    if html_content is None or html_content == "":
        return ""
    # 正则表达式模式用于匹配任何标签内的文本内容
    cleaned_text = re.sub(r'<[^>]+>', '', html_content)
    non_ascii_pattern = re.compile(r'[^\x00-\x7F]+')
    # 使用正则表达式移除所有的非ASCII字符
    cleaned_text_without_unicode = non_ascii_pattern.sub('', cleaned_text)
    return cleaned_text_without_unicode.strip()


def kill_processes_by_name(process_name_keyword):
    """根据进程名称关键字杀掉相关进程"""
    for proc in psutil.process_iter(attrs=["name"]):
        try:
            if process_name_keyword.lower() in proc.info["name"].lower():
                print(f"正在终止进程: {proc.info['name']} (PID: {proc.info['pid']})")
                proc.terminate()  # 结束进程
                proc.wait(timeout=3)  # 等待进程结束
        except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
            pass


def check_time_in_hour(key_hours=None) -> bool:
    if key_hours is None:
        key_hours = [1, 5, 9, 13, 17, 21]
    now = datetime.now()
    current_hour = now.hour
    return current_hour in key_hours


if __name__ == '__main__':
    pass